package com.hhd.pdf.components.sort;

import com.hhd.pdf.CommonUtils;
import com.hhd.pdf.variable.DynamicFormula;
import com.hhd.pdf.variable.VariableContext;
import lombok.Getter;
import lombok.Setter;
import org.dom4j.Attribute;
import org.dom4j.Element;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

@Component
public class PdfListSortor {
    @Autowired
    @Lazy
    List<SortBean> sortBeanList;

    public List<VariableContext> sort(List<VariableContext> childContexts,
                                      Element element,
                                      VariableContext rootVariableContext) {
        List<Attribute> attributes = getAttributes(element);
        if (CommonUtils.isEmpty(attributes)) return childContexts;

        SortBean sortBean = getSortBean(element);
        List<SortInvoker> sortInvokers = childContexts.stream()
                .map(c -> this.createSortInvoker(c, attributes)).filter(s -> {
                    s.setComparable(sortBean.getSortIndex(s.getArgs()));
                    return true;
                }).filter(s -> Objects.nonNull(s.getComparable())).collect(Collectors.toList());
        sortInvokers.sort((o1, o2) -> o1.getComparable().compareTo(o2.getComparable()));
        return sortInvokers.stream().map(SortInvoker::getContext).collect(Collectors.toList());
    }

    private List<Attribute> getAttributes(Element element) {
        List<Attribute> attributes = element.attributes();
        attributes = attributes.stream().filter(this::isSortFieldName).collect(Collectors.toList());
        return attributes;
    }

    private SortBean getSortBean(Element element) {
        String sortBeanName = element.attributeValue("sortBean");
        if (CommonUtils.isEmpty(sortBeanName)) {
            sortBeanName = "default";
        }
        SortBean sortBean = getSortBean(sortBeanName);
        return sortBean;
    }

    private SortBean getSortBean(String sortBeanName) {
        for (SortBean sortBean : sortBeanList) {
            if (sortBean.getSortBeanName().equals(sortBeanName)) {
                return sortBean;
            }
        }
        throw new RuntimeException("没有找到排序bean: " + sortBeanName);
    }

    public SortInvoker createSortInvoker(VariableContext context, List<Attribute> attributes) {
        HashMap<String, Object> map = new HashMap<>();
        for (Attribute attribute : attributes) {
            String value = attribute.getValue();
            String name = attribute.getName();

            DynamicFormula<Object> formula = DynamicFormula.formula(value, Object.class);
            context.execute(formula);
            map.put(name, formula.getFormulaValue());
        }
        return new SortInvoker(map, context);
    }

    private boolean isSortFieldName(Attribute attribute) {
        String fieldName = attribute.getName();
        if (CommonUtils.isEmpty(fieldName)) return false;
        return fieldName.toLowerCase().startsWith("sortfield");
    }

    @Getter
    static class SortInvoker {
        private final HashMap<String, Object> args;
        private final VariableContext context;
        @Setter
        private Comparable comparable;

        public SortInvoker(HashMap<String, Object> args,
                           VariableContext context) {
            this.args = args;
            this.context = context;
        }
    }
}
